【Java 数据结构】二叉树的经典面试题 (图解)

您所在的位置:网站首页 java数据结构 面试题 【Java 数据结构】二叉树的经典面试题 (图解)

【Java 数据结构】二叉树的经典面试题 (图解)

2024-07-09 13:09| 来源: 网络整理| 查看: 265

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

欢迎志同道合的朋友一起加油喔🦾🦾🦾 

目录

1. 相同的树

2. 另一颗树的子树

3.翻转二叉树

4. 平衡二叉树

5.对称二叉树

6.层序遍历

7. 二叉树的构建及遍历

8. 二叉树的最近公共祖先

 (1)方法一的代码

    (2) 方法二的代码

9. 从前序遍历与中序遍历序列构造二叉树

10.  从中序遍历与后序遍历序列构造二叉树

11. 根据二叉树创建字符串

1. 相同的树

●题目展示

●写题链接:  100. 相同的树 - 力扣(LeetCode)

●解题思路:两棵树同时递归, 每遍历到一个结点就判断    1️⃣当 两个结点p, q, 一个为空一个不为空时, 返回 false    2️⃣当 两个结点p, q, 的val值不同时, 返回 false    3️⃣当 两个结点p, q, 同时遍历到空结点时, 说明 p, q 的所有祖先点相同, 返回 true

⚠️⚠️⚠️注意:         不能 p, q, 同时不为空且值相同时就返回 true, 因为有可能这个结点暂时相同, 但子树的结点还不能相同, 一定是当 p, q, 同时遍历到空结点时, 才说明这一路的结点没有返回 false, 那么此时 p, q 的所有祖先点相同, 才能返回true

        ●图解:

 ●实现代码:

时间复杂度:O(min⁡(m,n)),其中 m 和 n 分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。

空间复杂度:O(min⁡(m,n)),其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。

public boolean isSameTree(TreeNode p, TreeNode q) { // p, q, 有其中一个不为空 if ( (p == null && q != null ) || (p != null && q == null) ) { return false; } // p, q, 都为空的情况 if (p == null && q == null) { return true; } // val不相同的情况 if (p.val != q.val) { return false; } // 左右子树都要判断 return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); }

        ●递归过程演示:        

2. 另一颗树的子树

●题目展示

●写题链接:另一颗数的子树

●解题思路:

上一题就是 判断两棵二叉树是否相同, 判断一棵树是否是另一颗的子树, 只需要遍历以 root 为根的树的每一个结点, 和以 subRoot 为根的树, 只要是相同的树则说明 root 这棵树中有 subRoot 这棵树, 所以上一题的代码可以直接拿来用

题目描述中说 tree 也可以看做它自身的一棵子树 , 说明: 如果给定的 root 和 subRoot 本身就是相同的树, 也符合题目要求, 所以首先要对给定的 root 和 subRoot 判断是否为同一棵树 然后利用子问题思想: 让 root 的左右子树递归判断是否存在一个结点和 subRoot 是相同的树

⚠️⚠️⚠️注意: 虽然题目给定两个树的结点范围是[1,2000], 说明两棵树都不为空, 但是不能省略代码中对 root 和 sunRoot 的判空, 因为: 1️⃣在上一题分析过, 当 p, q, 同时遍历到空结点时, 说明 p, q 的所有祖先点相同, 返回 true, 所以 root 和subRoot 都需要遍历到空结点 2️⃣还有一种情况是 root 这棵树的所有结点都遍历完了也不满足和 subRoot 是同一棵树, 所以要返回 false

●图解:

 ●实现代码:时间复杂度O(s * t),左边这棵树的每一个结点都要与右边树的每一个结点比较

public boolean isSubtree(TreeNode root, TreeNode subRoot) { // 防止空指针异常 if(root == null || subRoot == null) { return false; } if(isSameTree(root,subRoot)) { return true; } // 遍历,左右子树有一边满足条件即可 return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot); } public boolean isSameTree(TreeNode p, TreeNode q) { // p, q, 有其中一个不为空 if ( (p == null && q != null ) || (p != null && q == null) ) { return false; } // val不相同的情况 if (p.val != q.val) { return false; } // p, q, 都为空的情况 if (p == null && q == null) { return true; } // 左右子树都要判断 return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); }

3.翻转二叉树

●题目展示

●写题链接:力扣

●解题思路: 

交换一下左右节点,然后再递归的交换左节点,右节点 根据动画图我们可以总结出递归的两个条件如下:

终止条件:当前节点为 null 时返回 交换当前节点的左右节点,再递归的交换当前节点的左节点,递归的交换当前节点的右节点

●图解:   

  ●实现代码:

时间复杂度:每个元素都必须访问一次,所以是 O(n)

空间复杂度:最坏的情况下,需要存放 O(h)个函数调用(h是树的高度),所以是 O(h)

class Solution { public TreeNode invertTree(TreeNode root) { //递归函数的终止条件,节点为空时返回 if(root==null) { return null; } //下面三句是将当前节点的左右子树交换 TreeNode tmp = root.right; root.right = root.left; root.left = tmp; //递归交换当前节点的 左子树 invertTree(root.left); //递归交换当前节点的 右子树 invertTree(root.right); //函数返回时就表示当前这个节点,以及它的左右子树 //都已经交换完了 return root; } } 4. 平衡二叉树

●题目展示

●写题链接:力扣

●解题思路: 这个题需要借助求高度的代码,求平衡二叉树其实思路很简单,只要计算根结点的这棵树的左子树的高度和右子树的高度,然后相减判断是否 leftR ? leftH+1 : leftR+1; } public boolean isBalanced(TreeNode root) { if(root == null) return true; int leftH = height(root.left);//左树的高度 int rightH = height(root.right);//右树的高度 //求出左右子树的高度后,判断差值是否 inRight 的时候,说明没有了左树或者右树

  ●实现代码:

class Solution { public int preIndex = 0; public TreeNode buildTree(int[] preorder, int[] inorder) { return buildTreeChild(preorder,inorder,0,inorder.length-1); } private TreeNode buildTreeChild(int[] preorder, int[] inorder,int inbegin,int inend){ //没有了左树或者没有了右树 if(inbegin > inend) { return null; } TreeNode root = new TreeNode(preorder[preIndex]); //找到当前根节点 在中序遍历中的位置 int rootIndex = findInorder(inorder,preorder[preIndex],inbegin,inend); preIndex++; root.left = buildTreeChild(preorder, inorder,inbegin,rootIndex-1); root.right = buildTreeChild(preorder, inorder,rootIndex+1,inend); return root; } private int findInorder(int[] inorder,int val,int inbegin,int inend){ for(int i = inbegin; i inend) { return null; } TreeNode root = new TreeNode(postorder[postIndex]); //找到当前根节点 在中序遍历中的位置 int rootIndex = findInorder(inorder,postorder[postIndex],inbegin,inend); postIndex--; root.right = buildTreeChild(postorder, inorder,rootIndex+1,inend); root.left = buildTreeChild(postorder, inorder,inbegin,rootIndex-1); return root; } private int findInorder(int[] inorder,int val,int inbegin,int inend){ for(int i = inbegin; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3